/*
base64.c
offer base64 encode and decode function
designed by lunanting

------------------------
2020-09-09 13:06:32
create file
------------------------
*/
#include "base64.h"


const char Base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";



/*
base64 encode data
param:
    data:encode data
    len:encode data length
    endata:encoded data
    enlen:encoded data length
*/
void base64_encode(char *data,int len,char *endata,int *enlen){
    int i,j;
	//1、首先3字节组成1组，然后转换成4字节1组
	for(i = 0,j = 0;i < (len/3)*3;i = i + 3,j = j + 4)
	{
		endata[j] = 0;    //清除要做操作缓冲，其实这里没必要，可以去掉
		endata[j + 1] = 0;
		endata[j + 2] = 0;
		endata[j + 3] = 0;
		endata[j] = data[i] >> 2;
		endata[j + 1] = (((data[i]&0x03) << 4) | (data[i + 1] >> 4));
		endata[j + 2] = (((data[i + 1]&0x0F) << 2) | ((data[i + 2]&0xC0) >> 6));
		endata[j + 3] = (data[i + 2]&0x3F);
	}
	//2、其次对照Base64编码表，转换成对应字符编码
	for(i = 0;i < j;i++)
	{
		endata[i] = Base64[endata[i]];
	}
	if((len%3) == 1)//说明最后还有1个字节剩余，剩余1个字节，最后转换成Base64编码时最后要补2个'='字符，形成4字节1组，这样最后编码数据就是4的倍数
	{
		endata[i] = 0;    //清除要操作缓冲
		endata[i + 1] = 0;
		endata[i + 2] = 0;
		endata[i + 3] = 0;
		endata[i] = data[len - 1] >> 2;
		endata[i + 1] = ((data[len - 1]&0x03) << 4);
		endata[i] = Base64[endata[i]];
		endata[i + 1] = Base64[endata[i + 1]];
		endata[i + 2] = '=';
		endata[i + 3] = '=';
		i = i + 4;
	}
	if((len%3) == 2)//说明最后还有2个字节剩余，剩余2个字节，最后转换成Base64编码时最后要补1个'='字，形成4字节1组，这样最后编码数据就是4的倍数
	{
		endata[i] = 0;    //清除要操作缓冲
		endata[i + 1] = 0;
		endata[i + 2] = 0;
		endata[i + 3] = 0;
		endata[i] = data[len - 2] >> 2;
		endata[i + 1] = (((data[len - 2]&0x03) << 4) | (data[len - 1] >> 4));
		endata[i + 2] = (data[len - 1]&0x0F) << 2;
		endata[i] = Base64[endata[i]];
		endata[i + 1] = Base64[endata[i + 1]];
		endata[i + 2] = Base64[endata[i + 2]];
		endata[i + 3] = '=';
		i = i + 4;
	}
    *enlen=i;
}



/*
decode base64
base64 解码
param:
    data:decode data
    len:decode data length
    dedata:decoded data
    delen:decoded data length
return:
    0=success
*/
int base64_decode(char *data,int len,char *dedata,int *delen){
    int i,j;
	int tlength = 0;
    char fill_count=0;
	char buff[128] = {0};
	
	//1、首先去掉最后1个或者2个'='字符，最多就是2个
	for(i = 0;i < 2;i++)
	{
		if(data[len - 1] == '=')
		{
		    len--;
            fill_count ++;
		}
        else
        {
            break;
        }
	}
	for(i = 0;i < len;i++)
	{
		for(j = 0;j < 64;j++)
		{
			if(*(data + i) == *(Base64 + j))
			{
				break;
			}
		}
		if(j == 64)//传输数据里面有错误数据，数据没在base64编码对照表里面
		{
			return -1;
		}
		buff[i] = j;//找对对应索引值保存起来，为后面合成数据
	}
	//判断数据是否够4的倍数，不够补齐，补0x00
	if((i % 4) == 1)//说明数据最后剩余1数据，所以需要补充3个0x00,组成4的倍数
	{
	    buff[i] = 0x00;
		buff[i + 1] = 0x00;
		buff[i + 2] = 0x00;
		i = i + 3;
	}
	if((i % 4) == 2)//说明数据最后剩余2数据，所以需要补充2个0x00,组成4的倍数
	{
		buff[i] = 0x00;
		buff[i + 1] = 0x00;
		i = i + 2;
	}
	if((i % 4) == 3)//说明数据最后剩余3数据，所以需要补充1个0x00,组成4的倍数
	{
		buff[i] = 0x00;
		i = i + 1;
    }
    for(j = 0,tlength = 0;j < i;j = j + 4,tlength = tlength + 3)//上面数据已经组成4的倍数了，这样转换后的数据一定是3的倍数，这样解码后数据可能比原来多几个0x00数据，如果你不希望多出几个0x00,其实你也可以不组成4的倍数，我这里主要是为了方便解码
    {
        dedata[tlength] = (buff[j] << 2) | ((buff[j + 1]&0x30) >> 4);
        dedata[tlength + 1] = (((buff[j + 1]&0x0F) << 4) | ((buff[j + 2]&0x3C) >> 2));
        dedata[tlength + 2] = (((buff[j + 2]&0x03) << 6) | buff[j + 3]);		
    }
    *delen=tlength-fill_count;
    return 0;
}




//end of the file
